// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Matrix4.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Robotics.Numerics
{
    using System;
    using System.Runtime.Serialization;

    /// <summary>
    /// Defines a 4x4 matrix
    /// </summary>
    [DataContract]
    public class Matrix4
    {
        /// <summary>
        /// Size of the matrix
        /// </summary>
        private const int MatrixSize = 4;

        /// <summary>
        /// Private values of the 3x3 array
        /// </summary>
        private double[,] elements = new double[MatrixSize, MatrixSize];

        /// <summary>
        /// Used only for serialization and deserialization, since multi dimensional array serialization is 
        /// not supported. Do not use for any other purpose
        /// </summary>
        [DataMember]
        private double[] serializedElements;

        /// <summary>
        /// Initializes a new instance of the <see cref="Matrix4"/> class.
        /// </summary>
        public Matrix4()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Matrix4"/> class.
        /// value for each elements
        /// </summary>
        /// <param name="value">Value to set all entries to</param>
        public Matrix4(double value)
        {
            for (int i = 0; i < MatrixSize; i++)
            {
                for (int j = 0; j < MatrixSize; j++)
                {
                    this[i, j] = value;
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Matrix4"/> class.
        /// </summary>
        /// <param name="m">Matrix to be copied</param>
        public Matrix4(Matrix4 m)
        {
            if (m != null)
            {
                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        this[i, j] = m[i, j];
                    }
                }
            }
            else
            {
                throw new ArgumentNullException(
                    "m", "Can't initialize a new instance of the Matrix4 class using a null instance");
            }
        }

                /// <summary>
        /// Initializes a new instance of the Matrix4 class from a multidimensional array
        /// </summary>
        /// <param name="mat">Matrix to use for initialization</param>
        /// <exception cref="ArgumentNullException">Input matrix is null</exception>
        /// <exception cref="ArgumentException">Input matrix is not square 3x3 </exception>
        public Matrix4(double[,] mat)
        {
            if (null == mat)
            {
                throw new ArgumentNullException("Can't initialize Matrix4 with null matrix");
            }

            if (true == (mat.GetLength(0) != Matrix4.MatrixSize) || true == (mat.GetLength(1) != Matrix4.MatrixSize))
            {
                throw new ArgumentException(string.Format("Matrix4 requires a 4x4 matrix input is {0}x{1}", mat.GetLength(0), mat.GetLength(1)));
            }

            this.elements = mat;
        }

        /// <summary>
        /// Indexer for elements of the multi dimension array
        /// </summary>
        /// <param name="i">Row to access</param>
        /// <param name="j">Column to access</param>
        /// <returns>Value of the matrix at the specified row and column</returns>
        public double this[int i, int j]
        {
            get
            {
                if (((i >= 0) && (i < MatrixSize)) && ((j >= 0) && (j < MatrixSize)))
                {
                    return this.elements[i, j];
                }
                else
                {
                    throw new ArgumentOutOfRangeException(
                        "i or j", string.Format("Indexer not within valid range for this type"));
                }
            }

            set
            {
                if (((i >= 0) && (i < MatrixSize)) && ((j >= 0) && (j < MatrixSize)))
                {
                    this.elements[i, j] = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException(
                        "i or j", string.Format("Indexer not within valid range for this type"));
                }
            }
        }

        /// <summary>
        /// Create an identity matrix
        /// </summary>
        /// <returns>Identity matrix</returns>
        public static Matrix4 Identity()
        {
            Matrix4 identity = new Matrix4();

            for (int i = 0; i < MatrixSize; i++)
            {
                identity[i, i] = 1.0;
            }

            return identity;
        }

        /// <summary>
        /// Transpose a matrix
        /// </summary>
        /// <param name="m">Input matrix</param>
        /// <returns>Transposed matrix</returns>
        public static Matrix4 Transpose(Matrix4 m)
        {
            if (m == null)
            {
                return null;
            }
            else
            {
                Matrix4 transpose = new Matrix4();

                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        transpose[i, j] = m[j, i];
                    }
                }

                return transpose;
            }
        }

        /// <summary>
        /// The matrix multiplication operator
        /// </summary>
        /// <param name="m1">Left side</param>
        /// <param name="m2">Right side</param>
        /// <returns>The product of the operands. Null if any parameter is null</returns>
        public static Matrix4 operator *(Matrix4 m1, Matrix4 m2)
        {
            if ((m1 == null) || m2 == null)
            {
                throw new ArgumentNullException("Can't mulitply  Matrix4  using a null instance");
            }
            else
            {
                Matrix4 product = new Matrix4();

                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        for (int k = 0; k < MatrixSize; k++)
                        {
                            product[i, j] += m1[i, k] * m2[k, j];
                        }
                    }
                }

                return product;
            }
        }

        /// <summary>
        /// Multiplies a Matrix3 with a constant factor
        /// </summary>
        /// <param name="multiplier">Multiplication factor</param>
        /// <param name="m1">Matrix to multiply</param>
        /// <returns>The product of the operands. Null if any parameter is null</returns>
        public static Matrix4 operator *(double multiplier, Matrix4 m1)
        {
            if (m1 == null)
            {
                return null;
            }
            else
            {
                Matrix4 product = new Matrix4();

                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        product[i, j] = multiplier * m1[i, j];
                    }
                }

                return product;
            }
        }

        /// <summary>
        /// The matrix addition operator
        /// </summary>
        /// <param name="m1">Left side</param>
        /// <param name="m2">Right side</param>
        /// <returns>The sum of the operands. Null if any parameter is null</returns>
        public static Matrix4 operator +(Matrix4 m1, Matrix4 m2)
        {
            if ((m1 == null) || m2 == null)
            {
                throw new ArgumentNullException("Can't add a matrix4 with a matrix4 using a null matrix4 instance");
            }
            else
            {
                Matrix4 sum = new Matrix4();

                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        sum[i, j] = m1[i, j] + m2[i, j];
                    }
                }

                return sum;
            }
        }

        /// <summary>
        /// The matrix subtraction operator
        /// </summary>
        /// <param name="m1">Left side</param>
        /// <param name="m2">Right side</param>
        /// <returns>The difference between the operands. Null if any parameter is null</returns>
        public static Matrix4 operator -(Matrix4 m1, Matrix4 m2)
        {
            if ((m1 == null) || m2 == null)
            {
                throw new ArgumentNullException("Can't subtract a matrix4 with a matrix4 using a null matrix4 instance");
            }
            else
            {
                Matrix4 difference = new Matrix4();

                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        difference[i, j] = m1[i, j] - m2[i, j];
                    }
                }

                return difference;
            }
        }

        /// <summary>
        /// The matrix equality operator
        /// </summary>
        /// <param name="m1">Left side</param>
        /// <param name="m2">Right side</param>
        /// <returns>Result of the equality verification</returns>
        public static bool operator ==(Matrix4 m1, Matrix4 m2)
        {
            if (((m1 as object) == null) && (m2 as object) == null)
            {
                return true;
            }
            else if (((m1 as object) == null) || (m2 as object) == null)
            {
                return false;
            }
            else
            {
                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        if (Math.Abs(m1[i, j] - m2[i, j]) > MathConstants.ErrorEpsilon)
                        {
                            return false;
                        }
                    }
                }

                return true;
            }
        }

        /// <summary>
        /// The matrix equality operator
        /// </summary>
        /// <param name="m1">Left side</param>
        /// <param name="m2">Right side</param>
        /// <returns>Result of the equality verification</returns>
        public static bool operator !=(Matrix4 m1, Matrix4 m2)
        {
            return !(m1 == m2);
        }

        /// <summary>
        /// Matrix inversion from reflector since I don't feel like rewriting myself at the moment
        /// </summary>
        /// <param name="matrix">Matrix to invert</param>
        /// <returns>Inverted matrix</returns>
        public static Matrix4 Inverse(Matrix4 matrix)
        {
            return InverseInternal(ref matrix);
        }

        /// <summary>
        /// Calculate the matrix determinant
        /// </summary>
        /// <param name="matrix">The input matrix</param>
        /// <returns>The determinant value</returns>
        public static double Determinant(Matrix4 matrix)
        {
            double result = (matrix[0, 0] * matrix[1, 1] * matrix[2, 2] * matrix[3, 3])
                            + (matrix[0, 0] * matrix[1, 2] * matrix[2, 3] * matrix[3, 1])
                            + (matrix[0, 0] * matrix[1, 3] * matrix[2, 1] * matrix[3, 2])
                            + (matrix[0, 1] * matrix[1, 0] * matrix[2, 3] * matrix[3, 2])
                            + (matrix[0, 1] * matrix[1, 2] * matrix[2, 0] * matrix[3, 3])
                            + (matrix[0, 1] * matrix[1, 3] * matrix[2, 2] * matrix[3, 0])
                            + (matrix[0, 2] * matrix[1, 0] * matrix[2, 1] * matrix[3, 3])
                            + (matrix[0, 2] * matrix[1, 1] * matrix[2, 3] * matrix[3, 0])
                            + (matrix[0, 2] * matrix[1, 3] * matrix[2, 0] * matrix[3, 1])
                            + (matrix[0, 3] * matrix[1, 0] * matrix[2, 2] * matrix[3, 1])
                            + (matrix[0, 3] * matrix[1, 1] * matrix[2, 0] * matrix[3, 2])
                            + (matrix[0, 3] * matrix[1, 2] * matrix[2, 1] * matrix[3, 0])
                            - (matrix[0, 0] * matrix[1, 1] * matrix[2, 3] * matrix[3, 2])
                            - (matrix[0, 0] * matrix[1, 2] * matrix[2, 1] * matrix[3, 3])
                            - (matrix[0, 0] * matrix[1, 3] * matrix[2, 2] * matrix[3, 1])
                            - (matrix[0, 1] * matrix[1, 0] * matrix[2, 2] * matrix[3, 3])
                            - (matrix[0, 1] * matrix[1, 2] * matrix[2, 3] * matrix[3, 0])
                            - (matrix[0, 1] * matrix[1, 3] * matrix[2, 0] * matrix[3, 2])
                            - (matrix[0, 2] * matrix[1, 0] * matrix[2, 3] * matrix[3, 1])
                            - (matrix[0, 2] * matrix[1, 1] * matrix[2, 0] * matrix[3, 3])
                            - (matrix[0, 2] * matrix[1, 3] * matrix[2, 1] * matrix[3, 0])
                            - (matrix[0, 3] * matrix[1, 0] * matrix[2, 1] * matrix[3, 2])
                            - (matrix[0, 3] * matrix[1, 1] * matrix[2, 2] * matrix[3, 0])
                            - (matrix[0, 3] * matrix[1, 2] * matrix[2, 0] * matrix[3, 1]);

            return result;
        }

        /// <summary>
        /// Overrides the default base Equals implementation
        /// </summary>
        /// <param name="obj">The object to compare</param>
        /// <returns>False if the object is not a Matrix4 instance or is one that differs from the current instance</returns>
        public override bool Equals(object obj)
        {
            if (obj is Matrix4)
            {
                return this == (obj as Matrix4);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Overrides the default GetHashCode implementation
        /// </summary>
        /// <returns>Hash value for the matrix</returns>
        public override int GetHashCode()
        {
            double hashSeed;
            int hash = 0;
            unchecked
            {
                int elementIndex = 0;
                for (int i = 0; i < MatrixSize; i++)
                {
                    for (int j = 0; j < MatrixSize; j++)
                    {
                        elementIndex++;

                        if (this[i, j] != 0.0)
                        {
                            hashSeed = elementIndex * this[i, j];
                        }
                        else
                        {
                            hashSeed = elementIndex;
                        }

                        hashSeed *= hashSeed;
                        if (elementIndex == 1)
                        {
                            hash = hashSeed.GetHashCode();
                        }
                        else
                        {
                            hash ^= hashSeed.GetHashCode();
                        }
                    }
                }
            }

            return hash;
        }

        /// <summary>
        /// Create a string representation of Matrix4
        /// </summary>
        /// <returns>The formatted string</returns>
        public override string ToString()
        {
            return string.Format(
                "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}", 
                this[0, 0], 
                this[0, 1], 
                this[0, 2], 
                this[0, 3], 
                this[1, 0], 
                this[1, 1], 
                this[1, 2], 
                this[1, 3], 
                this[2, 0], 
                this[2, 1], 
                this[2, 2], 
                this[2, 3], 
                this[3, 0], 
                this[3, 1], 
                this[3, 2], 
                this[3, 3]);
        }

        /// <summary>
        /// Internal inversion method
        /// </summary>
        /// <param name="matrix">Matrix to invert</param>
        /// <returns>Inverted matrix</returns>
        private static Matrix4 InverseInternal(ref Matrix4 matrix)
        {
            Matrix4 inverse = new Matrix4();

            inverse[0, 0] = (matrix[1, 1] * matrix[2, 2] * matrix[3, 3]) + (matrix[1, 2] * matrix[2, 3] * matrix[3, 1])
                            + (matrix[1, 3] * matrix[2, 1] * matrix[3, 2])
                            - (matrix[1, 1] * matrix[2, 3] * matrix[3, 2])
                            - (matrix[1, 2] * matrix[2, 1] * matrix[3, 3])
                            - (matrix[1, 3] * matrix[2, 2] * matrix[3, 1]);

            inverse[0, 1] = (matrix[0, 1] * matrix[2, 3] * matrix[3, 2]) + (matrix[0, 2] * matrix[2, 1] * matrix[3, 3])
                            + (matrix[0, 3] * matrix[2, 2] * matrix[3, 1])
                            - (matrix[0, 1] * matrix[2, 2] * matrix[3, 3])
                            - (matrix[0, 2] * matrix[2, 3] * matrix[3, 1])
                            - (matrix[0, 3] * matrix[2, 1] * matrix[3, 2]);

            inverse[0, 2] = (matrix[0, 1] * matrix[1, 2] * matrix[3, 3]) + (matrix[0, 2] * matrix[1, 3] * matrix[3, 1])
                            + (matrix[0, 3] * matrix[1, 1] * matrix[3, 2])
                            - (matrix[0, 1] * matrix[1, 3] * matrix[3, 2])
                            - (matrix[0, 2] * matrix[1, 1] * matrix[3, 3])
                            - (matrix[0, 3] * matrix[1, 2] * matrix[3, 1]);

            inverse[0, 3] = (matrix[0, 1] * matrix[1, 3] * matrix[2, 2]) + (matrix[0, 2] * matrix[1, 1] * matrix[2, 3])
                            + (matrix[0, 3] * matrix[1, 2] * matrix[2, 1])
                            - (matrix[0, 1] * matrix[1, 2] * matrix[2, 3])
                            - (matrix[0, 2] * matrix[1, 3] * matrix[2, 1])
                            - (matrix[0, 3] * matrix[1, 1] * matrix[2, 2]);

            inverse[1, 0] = (matrix[1, 0] * matrix[2, 3] * matrix[3, 2]) + (matrix[1, 2] * matrix[2, 0] * matrix[3, 3])
                            + (matrix[1, 3] * matrix[2, 2] * matrix[3, 0])
                            - (matrix[1, 0] * matrix[2, 2] * matrix[3, 3])
                            - (matrix[1, 2] * matrix[2, 3] * matrix[3, 0])
                            - (matrix[1, 3] * matrix[2, 0] * matrix[3, 2]);

            inverse[1, 1] = (matrix[0, 0] * matrix[2, 2] * matrix[3, 3]) + (matrix[0, 2] * matrix[2, 3] * matrix[3, 0])
                            + (matrix[0, 3] * matrix[2, 0] * matrix[3, 2])
                            - (matrix[0, 0] * matrix[2, 3] * matrix[3, 2])
                            - (matrix[0, 2] * matrix[2, 0] * matrix[3, 3])
                            - (matrix[0, 3] * matrix[2, 2] * matrix[3, 0]);

            inverse[1, 2] = (matrix[0, 0] * matrix[1, 3] * matrix[3, 2]) + (matrix[0, 2] * matrix[1, 0] * matrix[3, 3])
                            + (matrix[0, 3] * matrix[1, 2] * matrix[3, 0])
                            - (matrix[0, 0] * matrix[1, 2] * matrix[3, 3])
                            - (matrix[0, 2] * matrix[1, 3] * matrix[3, 0])
                            - (matrix[0, 3] * matrix[1, 0] * matrix[3, 2]);

            inverse[1, 3] = (matrix[0, 0] * matrix[1, 2] * matrix[2, 3]) + (matrix[0, 2] * matrix[1, 3] * matrix[2, 0])
                            + (matrix[0, 3] * matrix[1, 0] * matrix[2, 2])
                            - (matrix[0, 0] * matrix[1, 3] * matrix[2, 2])
                            - (matrix[0, 2] * matrix[1, 0] * matrix[2, 3])
                            - (matrix[0, 3] * matrix[1, 2] * matrix[2, 0]);

            inverse[2, 0] = (matrix[1, 0] * matrix[2, 1] * matrix[3, 3]) + (matrix[1, 1] * matrix[2, 3] * matrix[3, 0])
                            + (matrix[1, 3] * matrix[2, 0] * matrix[3, 1])
                            - (matrix[1, 0] * matrix[2, 3] * matrix[3, 1])
                            - (matrix[1, 1] * matrix[2, 0] * matrix[3, 3])
                            - (matrix[1, 3] * matrix[2, 1] * matrix[3, 0]);

            inverse[2, 1] = (matrix[0, 0] * matrix[2, 3] * matrix[3, 1]) + (matrix[0, 1] * matrix[2, 0] * matrix[3, 3])
                            + (matrix[0, 3] * matrix[2, 1] * matrix[3, 0])
                            - (matrix[0, 0] * matrix[2, 1] * matrix[3, 3])
                            - (matrix[0, 1] * matrix[2, 3] * matrix[3, 0])
                            - (matrix[0, 3] * matrix[2, 0] * matrix[3, 1]);

            inverse[2, 2] = (matrix[0, 0] * matrix[1, 1] * matrix[3, 3]) + (matrix[0, 1] * matrix[1, 3] * matrix[3, 0])
                            + (matrix[0, 3] * matrix[1, 0] * matrix[3, 1])
                            - (matrix[0, 0] * matrix[1, 3] * matrix[3, 1])
                            - (matrix[0, 1] * matrix[1, 0] * matrix[3, 3])
                            - (matrix[0, 3] * matrix[1, 1] * matrix[3, 0]);

            inverse[2, 3] = (matrix[0, 0] * matrix[1, 3] * matrix[2, 1]) + (matrix[0, 1] * matrix[1, 0] * matrix[2, 3])
                            + (matrix[0, 3] * matrix[1, 1] * matrix[2, 0])
                            - (matrix[0, 0] * matrix[1, 1] * matrix[2, 3])
                            - (matrix[0, 1] * matrix[1, 3] * matrix[2, 0])
                            - (matrix[0, 3] * matrix[1, 0] * matrix[2, 1]);

            inverse[3, 0] = (matrix[1, 0] * matrix[2, 2] * matrix[3, 1]) + (matrix[1, 1] * matrix[2, 0] * matrix[3, 2])
                            + (matrix[1, 2] * matrix[2, 1] * matrix[3, 0])
                            - (matrix[1, 0] * matrix[2, 1] * matrix[3, 2])
                            - (matrix[1, 1] * matrix[2, 2] * matrix[3, 0])
                            - (matrix[1, 2] * matrix[2, 0] * matrix[3, 1]);

            inverse[3, 1] = (matrix[0, 0] * matrix[2, 1] * matrix[3, 2]) + (matrix[0, 1] * matrix[2, 2] * matrix[3, 0])
                            + (matrix[0, 2] * matrix[2, 0] * matrix[3, 1])
                            - (matrix[0, 0] * matrix[2, 2] * matrix[3, 1])
                            - (matrix[0, 1] * matrix[2, 0] * matrix[3, 2])
                            - (matrix[0, 2] * matrix[2, 1] * matrix[3, 0]);

            inverse[3, 2] = (matrix[0, 0] * matrix[1, 2] * matrix[3, 1]) + (matrix[0, 1] * matrix[1, 0] * matrix[3, 2])
                            + (matrix[0, 2] * matrix[1, 1] * matrix[3, 0])
                            - (matrix[0, 0] * matrix[1, 1] * matrix[3, 2])
                            - (matrix[0, 1] * matrix[1, 2] * matrix[3, 0])
                            - (matrix[0, 2] * matrix[1, 0] * matrix[3, 1]);

            inverse[3, 3] = (matrix[0, 0] * matrix[1, 1] * matrix[2, 2]) + (matrix[0, 1] * matrix[1, 2] * matrix[2, 0])
                            + (matrix[0, 2] * matrix[1, 0] * matrix[2, 1])
                            - (matrix[0, 0] * matrix[1, 2] * matrix[2, 1])
                            - (matrix[0, 1] * matrix[1, 0] * matrix[2, 2])
                            - (matrix[0, 2] * matrix[1, 1] * matrix[2, 0]);

            Matrix4 result = null;

            double det = Determinant(matrix);
            if (Math.Abs(det) > MathConstants.ErrorEpsilon)
            {
                result = (1.0 / det) * inverse;
            }

            return result;
        }

        /// <summary>
        /// 2 dimensional arrays are not serializable so unroll the elements during serialization
        /// into a single dimension array
        /// </summary>
        /// <param name="context">Deserialization context (unused).</param>
        [OnSerializing]
        private void OnSerializing(StreamingContext context)
        {
            this.serializedElements = new double[Matrix4.MatrixSize * Matrix4.MatrixSize];
            int k = 0;

            for (int i = 0; i < Matrix4.MatrixSize; ++i)
            {
                for (int j = 0; j < Matrix4.MatrixSize; ++j)
                {
                    this.serializedElements[k++] = this.elements[i, j];
                }
            }
        }

        /// <summary>
        /// 2 dimensional arrays are not serializable so populate from the single dimensional
        /// dimension array that was serialized
        /// </summary>
        /// <param name="context">Deserialization context (unused).</param>
        [OnDeserialized]
        private void OnDeserializied(StreamingContext context)
        {
            int k = 0;
            this.elements = new double[Matrix4.MatrixSize, Matrix4.MatrixSize];

            for (int i = 0; i < Matrix4.MatrixSize; ++i)
            {
                for (int j = 0; j < Matrix4.MatrixSize; ++j)
                {
                    this.elements[i, j] = this.serializedElements[k++];
                }
            }
        }
    }
}
